package com.yanqu.road.server.manger.activity.daomu;

import com.alibaba.fastjson.JSONObject;
import com.yanqu.road.entity.activity.daomu.*;
import com.yanqu.road.entity.activity.daomu.config.*;
import com.yanqu.road.entity.activity.daomu.enums.*;
import com.yanqu.road.entity.activity.daomu.param.DaoMuAttReportRes;
import com.yanqu.road.entity.activity.daomu.param.DaoMuCountSkillHurtReq;
import com.yanqu.road.entity.activity.daomu.param.DaoMuCreateNpcRes;
import com.yanqu.road.entity.activity.daomu.param.DaoMuOpenBoxRes;
import com.yanqu.road.entity.activity.daomu.skillstrategy.active.ISkillActiveStrategy;
import com.yanqu.road.entity.activity.daomu.skillstrategy.active.impl.*;
import com.yanqu.road.entity.activity.daomu.skillstrategy.active.impl.npc.*;
import com.yanqu.road.entity.activity.daomu.skillstrategy.passive.ISkillPassiveStrategy;
import com.yanqu.road.entity.activity.daomu.skillstrategy.passive.impl.*;
import com.yanqu.road.entity.activity.daomu.skillstrategy.passive.req.DaoMuPassiveSkillCountAttributeReq;
import com.yanqu.road.entity.enums.eActivityConfigType;
import com.yanqu.road.entity.enums.eActivityType;
import com.yanqu.road.entity.enums.eLogMoneyType;
import com.yanqu.road.exception.BusinessException;
import com.yanqu.road.logic.config.ChannelConfig;
import com.yanqu.road.logic.config.GameConfig;
import com.yanqu.road.pb.activity.DaoMuProto;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.player.CurrencyModule;
import com.yanqu.road.server.manger.activity.daomu.pb.DaoMuActivityPb;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.UUIDHelper;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;
import com.yanqu.road.utils.string.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.mina.util.ConcurrentHashSet;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

public class DaoMuActivityPveRoom {

    protected static Logger logger = LogManager.getLogger(DaoMuActivityPveRoom.class.getName());

    //配置
    private DaoMuActivityConfig daoMuActivityConfig;

    //进行的关卡
    private int passesId;

    //房间号
    private String roomId;

    //创建时间
    private long createTime;

    //等级
    private int level = 1;

    //经验
    private int exp = 0;

    //客户端请求生成NPC频率，5秒一次
    private int createNpcFrequency = 5;

    //暂停时长（毫秒），热更临时处理，用这个字段记录攻击boss和被boss攻击的次数
    private long stopTime = 0;

    //打boss开始时间
    private long battleBossStartTime = 0;

    //打boss时长（毫秒）
    private long battleBossTime = 0;

    //解锁的技能MAP.k:技能id，v:技能
    private Map<Integer, DaoMuSkill> unlockSkillListMap;

    //主动技能MAP。k:技能id，v:技能
    private Map<Integer, DaoMuSkill> activeSkillMap = new ConcurrentHashMap<>();

    //被动技能MAP。k:技能id，v:技能
    private Map<Integer, DaoMuSkill> passiveSkillMap = new ConcurrentHashMap<>();

    //升级后，待选择技能次数
    private AtomicInteger waitSelectSkillNum = new AtomicInteger(0);

    //NPC最大id
    private AtomicLong npcMaxId = new AtomicLong(0);

    //NPC MAP
    private Map<Long, DaoMuNpc> npcMap = new ConcurrentHashMap<>();
    private AtomicInteger killNpcNum = new AtomicInteger(0);//正常死亡的NPC数量
    private AtomicInteger clearNpcNum = new AtomicInteger(0);//清除的NPC数量

    //减少的血量
    private long reduceHp = 0;

    //结算信息
    private DaoMuStatementInfo daoMuStatementInfo = null;

    //局内道具最大ID
    private AtomicInteger battlePropMaxId = new AtomicInteger(0);

    //局内道具
    private Map<Integer, DaoMuBattlePropItem> battlePropMap = new ConcurrentHashMap<>();

    //属性MAP
    private Map<Integer, DaoMuAttribute> attributeMap;

    //记录陶罐的坐标
    private Set<String> clayPositionSet = new ConcurrentHashSet<>();

    //记录刷新NPC的秒数
    private Set<Integer> createNpcSecondSet = new ConcurrentHashSet<>();

    //击败的悬赏的npcId
    private Set<Integer> offerRewardNpcIdSet = new LinkedHashSet<>();

    //上次自动增加经验时间（毫秒数）
    private int lastAutoAddExpTime = 0;

    //上次自动回血时间（毫秒数）
    private int lastAutoAddHpTime = 0;

    //已经复活的次数
    private int resurgenceNum = 0;

    //已全选技能次数
    private int skillSelectAllTime = 0;

    //可全选技能次数
    private AtomicInteger canSkillSelectAllTime = new AtomicInteger(0);

    RandomHelper randomHelper = new RandomHelper();

    //重新随机技能次数
    private int randomSelectSkillNum = 0;

    //主动技能策略
    private static Map<Integer, ISkillActiveStrategy> skillActiveStrategyMap = new HashMap<>();
    static {
        skillActiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_10100.getId(), new SkillShotGunStrategy());
        skillActiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_10200.getId(), new SkillGildingStrategy());
        skillActiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_10300.getId(), new SkillBlackGoldKnifeStrategy());
        skillActiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_10400.getId(), new SkillFishStrategy());
        skillActiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_10500.getId(), new SkillGhostSealStrategy());
        skillActiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_10600.getId(), new SkillSixAngleBellStrategy());
        skillActiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_10700.getId(), new SkillStoneStrategy());
        skillActiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_10700.getId(), new SkillStoneStrategy());
        skillActiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_10800.getId(), new SkillGoldTigerStrategy());
        skillActiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_10900.getId(), new SkillFoxMaskStrategy());
        skillActiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_11000.getId(), new SkillBronzeBellStrategy());
        skillActiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_11100.getId(), new SkillFiveKingCoinStrategy());
        skillActiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_11200.getId(), new SkillQinKingSwordStrategy());
        skillActiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_11300.getId(), new SkillLotusSwordStrategy());
        skillActiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_11400.getId(), new SkillWeightyStrategy());
        skillActiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_11500.getId(), new SkillDragonAxeStrategy());
        skillActiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_11600.getId(), new SkillCinnabarStrategy());
        skillActiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_11700.getId(), new SkillSwordStrategy());
        skillActiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_11800.getId(), new SkillEightPictureStrategy());

        skillActiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_100.getId(), new SkillNpcTouchStrategy());
        skillActiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_200.getId(), new SkillNpcArrowStrategy());
        skillActiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_201.getId(), new SkillNpcArrowStrategy());
        skillActiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_300.getId(), new SkillNpcBoonStrategy());
        skillActiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_500.getId(), new SkillNpcSprintStrategy());
        skillActiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_600.getId(), new SkillNpcPoisonStrategy());
        skillActiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_800.getId(), new SkillNpcFlowerStrategy());
    }
    
    //被动技能策略
    private static Map<Integer, ISkillPassiveStrategy> skillPassiveStrategyMap = new HashMap<>();
    static {
        skillPassiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_20100.getId(), new SkillTouchGoldStrategy());
        skillPassiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_20200.getId(), new SkillNoteBookStrategy());
        skillPassiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_20300.getId(), new SkillKyLinStrategy());
        skillPassiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_20700.getId(), new SkillZombieStrategy());
        skillPassiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_20800.getId(), new SkillBranchStrategy());
        skillPassiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_20900.getId(), new SkillTurtleStrategy());
        skillPassiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_21000.getId(), new SkillBlackStrategy());
        skillPassiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_21100.getId(), new SkillMercuryStrategy());
        skillPassiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_21200.getId(), new SkillMeteoriteStrategy());
        skillPassiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_21300.getId(), new SkillJadeFigurineStrategy());
        skillPassiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_21400.getId(), new SkillShBeadStrategy());
        skillPassiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_21500.getId(), new SkillStoneBirdStrategy());
        skillPassiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_21600.getId(), new SkillLampStrategy());
        skillPassiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_21700.getId(), new SkillFourSheepStrategy());
        skillPassiveStrategyMap.put(DaoMuSkillEnum.DAO_MU_SKILL_21800.getId(), new SkillStoneClothesStrategy());
    }

    //技能等级关系
    private Map<Integer, Integer> specialSkillLevel;

    /**
     * 构造函数
     */
    public DaoMuActivityPveRoom(DaoMuActivityConfig daoMuActivityConfig, int passesId, Map<Integer, DaoMuSkill> skillMap, Map<Integer, DaoMuSkill> defaultSkillMap, Map<Integer, DaoMuAttribute> attributeMap, Map<Integer, Integer> specialSkillLevel) {
        //活动配置
        this.daoMuActivityConfig = daoMuActivityConfig;
        //创建房间号
        this.roomId = UUIDHelper.randomUUID("daomu");
        //创建时间
        this.createTime = System.currentTimeMillis();
        //进行的关卡
        this.passesId = passesId;
        //解锁的技能LIST
        this.unlockSkillListMap = skillMap;
        //初始化技能
        this.activeSkillMap.putAll(defaultSkillMap);
        //默认经验石id和数量,读取配置
        String defaultExpStr = this.daoMuActivityConfig.getDaoMuActivityConfigValue(eActivityConfigType.DAOMU_INITIAL_EXP_NUM);
        String[] defaultExpStrArr = defaultExpStr.split("=");
        int defaultExpStoneNum = Integer.valueOf(defaultExpStrArr[1]);
        int defaultExpStoneId = Integer.valueOf(defaultExpStrArr[0]);
        this.addBattleProp(defaultExpStoneId, defaultExpStoneNum, true, DaoMuPropSourceTypeEnum.DAO_MU_PROP_SOURCE_TYPE_START, 0);
        //注入属性
        this.attributeMap = attributeMap;
        //技能等级关系
        this.specialSkillLevel = specialSkillLevel;
    }

    /**
     * 获取初始随机种子
     * @return
     */
    public int getAttRandSeed() {
        return 0;
    }

    /**
     * 获取房间号
     * @return
     */
    public String getRoomId() {
        return roomId;
    }

    /**
     * 减少的血量
     * @return
     */
    public long getReduceHp() {
        return reduceHp;
    }

    /**
     * 获取属性map。无技能加成
     * @return
     */
    public Map<Integer, DaoMuAttribute> getAttributeMap() {
        return attributeMap;
    }

    /**
     * 主动技能
     * @return
     */
    public Map<Integer, DaoMuSkill> getActiveSkillMap() {
        return activeSkillMap;
    }

    /**
     * 辅助技能
     * @return
     */
    public Map<Integer, DaoMuSkill> getPassiveSkillMap() {
        return passiveSkillMap;
    }

    /**
     * 等级
     * @return
     */
    public int getLevel() {
        return level;
    }

    /**
     * 经验
     * @return
     */
    public int getExp() {
        return exp;
    }

    /**
     * 进行的关卡
     * @return
     */
    public int getPassesId() {
        return this.passesId;
    }

    /**
     * 获取房间创建时间
     * @return
     */
    public long getCreateTime() {
        return createTime;
    }

    /**
     * 获取已经复活的次数
     * @return
     */
    public int getResurgenceNum() {
        return resurgenceNum;
    }

    /**
     * 获取可全选技能次数
     */
    public int getCanSkillSelectAllTime() {
        return this.canSkillSelectAllTime.get();
    }

    /**
     * 增加可全选技能次数
     */
    public void addCanSkillSelectAllTime() {
        this.canSkillSelectAllTime.incrementAndGet();
    }

    /**
     * 减少可全选技能次数
     */
    public void reSkillSelectAllTime() {
        this.canSkillSelectAllTime.decrementAndGet();
    }

    /**
     * 已全选技能的次数
     * @return
     */
    public int getSkillSelectAllTime() {
        return skillSelectAllTime;
    }

    /**
     * 获取重随技能次数
     * @return
     */
    public int getRandomSelectSkillNum() {
        return randomSelectSkillNum;
    }

    /**
     * 增加全选技能的次数
     */
    public void addSkillSelectAllTime() {
        this.skillSelectAllTime++;
    }

    /**
     * 最大血量
     * @return
     */
    public long getTotalHp() {
        DaoMuAttribute maxHpAttribute = this.attributeMap.get(DaoMuAttributeEnum.ATTRIBUTE_HP.getType());
        //技能BUFF增加最大血量
        BigDecimal maxHp = this.buffHandlerMaxHpAdd(maxHpAttribute.getValue());
        if (maxHp.compareTo(maxHpAttribute.getMaxValue()) > 0) {
            return maxHpAttribute.getMaxValue().longValue();
        }
        return maxHp.longValue();
    }

    /**
     * 结算信息
     * @return
     */
    public DaoMuStatementInfo getDaoMuStatementInfo() {
        return daoMuStatementInfo;
    }

    /**
     * 击败的悬赏的NPC ID
     * @return
     */
    public Set<Integer> getOfferRewardNpcIdSet() {
        return offerRewardNpcIdSet;
    }

    /**
     * 增加血量
     * @param hp
     */
    public void addHp(long hp) {
        long newReduceHp = this.reduceHp - hp;
        if (newReduceHp < 0) {
            newReduceHp = 0;
        }
        this.reduceHp = newReduceHp;
    }

    /**
     * 减少血量
     * @param hp
     */
    public void reduceHp(long hp) {
        this.reduceHp += hp;
        //判断是否死亡
        if (this.reduceHp >= this.getTotalHp()) {
            //玩家死亡
            this.die();
        } else {
            //受伤回血
            this.buffHandlerHarmHpAdd();
        }
    }

    /**
     * 玩家死亡
     */
    private void die() {
        //结算
        DaoMuStatementInfo daoMuStatementInfo = new DaoMuStatementInfo();
        daoMuStatementInfo.setStatus(false);
        daoMuStatementInfo.setBattleTime(this.countBattleTime());
        daoMuStatementInfo.setKillNum(this.countKillNpcNum());
        daoMuStatementInfo.setResurgenceNum(this.resurgenceNum);
        this.daoMuStatementInfo = daoMuStatementInfo;
    }

    /**
     * 获取局内道具MAP
     * @return
     */
    public Map<Integer, DaoMuBattlePropItem> getBattlePropMap() {
        return battlePropMap;
    }

    /**
     * 解析局内道具。Property => Map<Integer, DaoMuBattlePropItem>
     * @param property
     * @param usableFlag 是否可使用
     * @return
     */
    private Map<Integer, DaoMuBattlePropItem> parsePropertyToBattleProp(Property property, boolean usableFlag, DaoMuPropSourceTypeEnum sourceTypeEnum, int sourceId) {
        Map<Integer, DaoMuBattlePropItem> result = new HashMap<>();
        for (Map.Entry<Integer, BigInteger> entry : property.getGoods().entrySet()) {
            for (int i = 0; i < entry.getValue().intValue(); i++) {
                DaoMuBattlePropItem daoMuBattlePropItem = new DaoMuBattlePropItem(this.battlePropMaxId.incrementAndGet(), entry.getKey(), usableFlag, sourceTypeEnum.getType(), sourceId);
                result.put(daoMuBattlePropItem.getBattlePropId(), daoMuBattlePropItem);
            }
        }
        return result;
    }

    /**
     * 添加局内道具
     * @param property
     * @param usableFlag 是否使用
     */
    private Map<Integer, DaoMuBattlePropItem> addBattleProp(Property property, boolean usableFlag, DaoMuPropSourceTypeEnum sourceTypeEnum, int sourceId) {
        //解析
        Map<Integer, DaoMuBattlePropItem> addBattlePropMap = this.parsePropertyToBattleProp(property, usableFlag, sourceTypeEnum, sourceId);
        //增加
        this.battlePropMap.putAll(addBattlePropMap);
        return addBattlePropMap;
    }

    /**
     * 添加局内道具
     * @param curioId
     * @param num
     * @param usableFlag 是否可使用
     * @return
     */
    private Map<Integer, DaoMuBattlePropItem> addBattleProp(int curioId, int num, boolean usableFlag, DaoMuPropSourceTypeEnum sourceTypeEnum, int sourceId) {
        Map<Integer, DaoMuBattlePropItem> result = new HashMap<>();
        for (int i = 0; i < num; i++) {
            DaoMuBattlePropItem addBattlePropMap = new DaoMuBattlePropItem(this.battlePropMaxId.incrementAndGet(), curioId, usableFlag, sourceTypeEnum.getType(), sourceId);
            this.battlePropMap.put(addBattlePropMap.getBattlePropId(), addBattlePropMap);
            result.put(addBattlePropMap.getBattlePropId(), addBattlePropMap);
        }
        return result;
    }

    /**
     * 使用道具
     * @param daoMuBattlePropItem
     */
    private boolean useProp(DaoMuBattlePropItem daoMuBattlePropItem) {
        if (daoMuBattlePropItem.isUsableFlag()) {
            //清除道具
            this.battlePropMap.remove(daoMuBattlePropItem.getBattlePropId());
            return true;
        }
        return false;
    }

    /**
     * 获取局内道具类型
     * @param battlePropId
     * @return
     */
    private int getBattlePropType(int battlePropId) {
        DaoMuBattlePropItem daoMuBattlePropItem = this.battlePropMap.get(battlePropId);
        if (daoMuBattlePropItem != null) {
            DaoMuCurioConfig daoMuCurioConfig = this.daoMuActivityConfig.getDaoMuCurioConfigMap().get(daoMuBattlePropItem.getCurioId());
            if (daoMuCurioConfig != null) {
                return daoMuCurioConfig.getType();
            }
        }
        return 0;
    }

    /**
     * 攻击NPC的伤害
     * @param daoMuSkill
     * @param daoMuNpc
     * @param skillHarmType
     * @param damageBuffMap
     * @param gameMillisecond
     * @param criticalFlag
     * @return
     */
    private long getAttNpcHurt(DaoMuSkill daoMuSkill, DaoMuNpc daoMuNpc, int skillHarmType, Map<Integer, DaoMuDamageBuff> damageBuffMap, int gameMillisecond, boolean criticalFlag) {
        //获取技能配置
        DaoMuSkillConfig daoMuSkillConfig = this.getRealDaoMuSkillConfig(daoMuSkill);
        //获取玩家属性
        Map<Integer, DaoMuAttribute> userAttribute = this.buildBattleAttribute(damageBuffMap, gameMillisecond);
        //获取NPC属性
        DaoMuNpcConfig daoMuNpcConfig = this.daoMuActivityConfig.getDaoMuNpcConfigMap().get(daoMuNpc.getNpcId());
        Map<Integer, DaoMuAttribute> npcAttribute = this.daoMuActivityConfig.buildAttributeMap(daoMuNpcConfig.getBasePara());
        //获取技能伤害
        return this.getAttHurt(daoMuSkillConfig, userAttribute, npcAttribute, skillHarmType, damageBuffMap, criticalFlag);
    }

    /**
     * 被攻击的伤害
     * @param skillUnId
     * @param daoMuNpc
     * @param skillHarmType
     * @param damageBuffMap
     * @param gameMillisecond
     * @param criticalFlag
     * @return
     */
    private long getBeAttHurt(int skillUnId, DaoMuNpc daoMuNpc, int skillHarmType, Map<Integer, DaoMuDamageBuff> damageBuffMap, int gameMillisecond, boolean criticalFlag) {
        //技能配置
        DaoMuSkillConfig daoMuSkillConfig = this.daoMuActivityConfig.getDaoMuSkillConfigMap().get(skillUnId);
        //获取NPC属性
        DaoMuNpcConfig daoMuNpcConfig = this.daoMuActivityConfig.getDaoMuNpcConfigMap().get(daoMuNpc.getNpcId());
        Map<Integer, DaoMuAttribute> npcAttribute = this.daoMuActivityConfig.buildAttributeMapByNpc(daoMuNpcConfig.getBasePara());
        //获取玩家属性
        Map<Integer, DaoMuAttribute> userAttribute = this.buildBattleAttribute(damageBuffMap, gameMillisecond);
        //获取技能伤害
        return this.getAttHurt(daoMuSkillConfig, npcAttribute, userAttribute, skillHarmType, damageBuffMap, criticalFlag);
    }

    /**
     * 获取伤害
     * @param daoMuSkillConfig 技能配置
     * @param myAttribute 攻击方属性
     * @param targetAttribute 对方属性
     * @param skillHarmType 技能伤害小类型
     * @param damageBuffMap 损害BUFF
     * @param criticalFlag 是否暴击
     * @return
     */
    private long getAttHurt(DaoMuSkillConfig daoMuSkillConfig, Map<Integer, DaoMuAttribute> myAttribute, Map<Integer, DaoMuAttribute> targetAttribute, int skillHarmType, Map<Integer, DaoMuDamageBuff> damageBuffMap, boolean criticalFlag) {
        //执行技能策略
        DaoMuCountSkillHurtReq req = new DaoMuCountSkillHurtReq();
        req.setDaoMuSkillConfig(daoMuSkillConfig);
        req.setSkillHarmType(skillHarmType);
        req.setAttributeMap(myAttribute);
        req.setTargetAttributeMap(targetAttribute);
        req.setDamageBuffMap(damageBuffMap);
        req.setCriticalFlag(criticalFlag);
        ISkillActiveStrategy skillStrategy = DaoMuActivityPveRoom.skillActiveStrategyMap.get(daoMuSkillConfig.getSkillId());
        return skillStrategy.countSkillHurt(req);
    }

    /**
     * 获取战斗属性，被动技能加成后的属性
     * @param damageBuffMap 对方损害BUFF MAP
     * @param gameMillisecond 游戏进行到第几毫秒
     * @return
     */
    public Map<Integer, DaoMuAttribute> buildBattleAttribute(Map<Integer, DaoMuDamageBuff> damageBuffMap, int gameMillisecond) {
        Map<Integer, DaoMuAttribute> attributeMap = new HashMap<>();
        for (DaoMuAttribute baseAttribute : this.attributeMap.values()) {
            DaoMuAttribute attribute = new DaoMuAttribute(baseAttribute.getId(), baseAttribute.getValue(), baseAttribute.getMaxValue());
            attributeMap.put(attribute.getId(), attribute);
        }
        //遍历辅助技能
        for (DaoMuSkill daoMuSkill : this.passiveSkillMap.values()) {
            //获取技能配置
            DaoMuSkillConfig daoMuSkillConfig = this.getRealDaoMuSkillConfig(daoMuSkill);
            //辅助技能策略-计算属性MAP
            ISkillPassiveStrategy skillPassiveStrategy = skillPassiveStrategyMap.get(daoMuSkill.getSkillId());
            if (skillPassiveStrategy != null) {
                DaoMuPassiveSkillCountAttributeReq req = new DaoMuPassiveSkillCountAttributeReq();
                req.setDaoMuSkill(daoMuSkill);
                req.setDaoMuSkillConfig(daoMuSkillConfig);
                req.setDamageBuffMap(damageBuffMap);
                req.setGameMillisecond(gameMillisecond);
                req.setAttributeMap(attributeMap);
                req.setActiveSkillMap(this.activeSkillMap);
                req.setPassiveSkillMap(this.passiveSkillMap);
                skillPassiveStrategy.countAttribute(req);
            }
        }
        //计算属性map
        for (DaoMuAttribute daoMuAttribute : attributeMap.values()) {
            daoMuAttribute.doAdd();
        }
        return attributeMap;
    }

    /**
     * 获取道具伤害。并使用掉道具
     * @param battlePropId
     * @return
     */
    private long getPropHurt(int battlePropId) {
        DaoMuBattlePropItem daoMuBattlePropItem = this.battlePropMap.get(battlePropId);
        if (daoMuBattlePropItem != null) {
            DaoMuCurioConfig daoMuCurioConfig = this.daoMuActivityConfig.getDaoMuCurioConfigMap().get(daoMuBattlePropItem.getCurioId());
            if (daoMuCurioConfig != null) {
                //判断是哪一种道具
                if (daoMuCurioConfig.getType() == DaoMuCurioTypeEnum.TYPE_BOMB.getType()) {
                    return Long.MAX_VALUE;
                }
                //后续新增伤害道具，在这里处理
            }
        }
        return 0L;
    }

    /**
     * 获取技能配置
     * @param daoMuSkill
     * @return
     */
    public DaoMuSkillConfig getRealDaoMuSkillConfig(DaoMuSkill daoMuSkill) {
        int skillId = daoMuSkill.getSkillId();
        int skillLevel = daoMuSkill.getSkillLevel();
        return this.getRealDaoMuSkillConfig(skillId, skillLevel);
    }

    /**
     * 获取技能配置
     * @param skillId
     * @param skillLevel
     * @return
     */
    private DaoMuSkillConfig getRealDaoMuSkillConfig(int skillId, int skillLevel) {
        //有特殊效果的等级
        String maxSpecialLevelStr = this.daoMuActivityConfig.getDaoMuActivityConfigValue(eActivityConfigType.DAOMU_LNNING_HAS_ASSISTIVE_SKILL_LEVEL_MAX);
        int fullLevel = Integer.parseInt(maxSpecialLevelStr);
        if (skillLevel >= fullLevel) {
            int maxLevel = this.specialSkillLevel.get(skillId);
            return this.daoMuActivityConfig.getSkillConfig(skillId, maxLevel);
        } else {
            return this.daoMuActivityConfig.getSkillConfig(skillId, skillLevel);
        }
    }

    /**
     * 创建NPC
     * @param second 第几秒 1, 5, 10, 15
     * @throws BusinessException
     */
    public DaoMuCreateNpcRes createNpc(int second) throws BusinessException {
        //判断秒数是否正确
        if (second % this.createNpcFrequency != 0 && second != 1) {
            throw BusinessException.newException(GameErrorCode.E_DAOMU_PVE_CREATE_NPC_SECOND_ERROR);
        }
        //判断该秒数是否刷新过
        if (this.createNpcSecondSet.contains(second)) {
            throw BusinessException.newException(GameErrorCode.E_DAOMU_PVE_CREATE_NPC_SECOND_EXIST_ERROR);
        }
        //判断是否进行到该秒
        long milliseconds = System.currentTimeMillis() - this.createTime;
        //游戏总时长 = 正常时间 + 暂停时间 + 打boss时间
        long gameTime = second * 1000 + this.battleBossTime;
        if (milliseconds < gameTime) {
            throw BusinessException.newException(GameErrorCode.E_DAOMU_PVE_CREATE_NPC_TIME_ERROR);
        }
        DaoMuCreateNpcRes result = new DaoMuCreateNpcRes();
        //生成BOSS
        DaoMuNpc boss = this.createNpcBoss(second);
        if (boss != null) {
            result.setBoss(boss);
            return result;
        }
        //生成小怪
        Map<Long, DaoMuNpc> mobs = this.createNpcMobs(second);
        result.setMobs(mobs);
        //生成特殊怪
        Map<Long, DaoMuNpc> special = this.createNpcSpecial(second);
        result.setSpecial(special);
        //记录刷新NPC秒数
        this.createNpcSecondSet.add(second);
        return result;
    }

    /**
     * 生成NPC：小怪
     * @param second 第几秒
     * @return
     */
    private Map<Long, DaoMuNpc> createNpcMobs(int second) {
        Map<Long, DaoMuNpc> npcMap = new ConcurrentHashMap<>();
        DaoMuMissionConfig daoMuMissionConfig = this.daoMuActivityConfig.getDaoMuMissionConfigMap().get(this.passesId);
        //获取小怪NPC
        Map<String, Integer> npcConfigMap = daoMuMissionConfig.getMobsNpc(second);
        if (npcConfigMap == null) {
            return npcMap;
        }
        //小怪 npc id
        int npcId = npcConfigMap.get("npcId");
        DaoMuNpcConfig daoMuNpcConfig = this.daoMuActivityConfig.getDaoMuNpcConfigMap().get(npcId);
        Map<Integer, DaoMuAttribute> attributeMap = this.daoMuActivityConfig.buildAttributeMapByNpc(daoMuNpcConfig.getBasePara());
        //判断生成NPC的数量是否达到最大值,【小怪】类型才需要判断
        int existNpcNum = this.countExistNpcNum();
        if (daoMuNpcConfig.getType() == DaoMuNpcTypeEnum.NPC_TYPE_MOBS.getType() && this.daoMuActivityConfig.checkNpcNumMax(existNpcNum)) {
            return npcMap;
        }
        //一波几只怪
        int oneWaveNum = daoMuNpcConfig.getOneWaveNum();
        //npc生成频率
        int npcFrequency = npcConfigMap.get("num");
        //第一秒的时候，特殊处理。第一秒只生成 1,2,3,4秒的数据，不包含第5秒
        int createNpcFrequency = this.createNpcFrequency;
        if (second == 1) {
            createNpcFrequency = this.createNpcFrequency - 1;
        }
        //遍历多少秒
        outer:
        for (int i = 0; i < createNpcFrequency; i++) {
            //每秒生成多少只
            int createSecond = second + i;//第几秒生成
            for (int j = 0; j < npcFrequency; j++) {
                for (int x = 0; x < oneWaveNum; x++) {
                    DaoMuNpc daoMuNpc = new DaoMuNpc();
                    daoMuNpc.setId(this.npcMaxId.incrementAndGet());
                    daoMuNpc.setNpcId(npcId);
                    daoMuNpc.setStatus(DaoMuNpcStatusEnum.NPC_STATUS_EXIST.getStatus());
                    daoMuNpc.setCreateTimeSecond(createSecond);
                    daoMuNpc.setAttributeMap(attributeMap);
                    //掉落的物品，先生成好
                    Property property = this.daoMuActivityConfig.getNpcDropProp(npcId);
                    Map<Integer, DaoMuBattlePropItem> addBattleProp = this.addBattleProp(property, false, DaoMuPropSourceTypeEnum.DAO_MU_PROP_SOURCE_TYPE_NPC, (int) daoMuNpc.getId());
                    daoMuNpc.setDropProp(addBattleProp);
                    //put npc
                    npcMap.put(daoMuNpc.getId(), daoMuNpc);
                    //判断生成NPC的数量是否达到最大值
                    existNpcNum++;
                    if (daoMuNpcConfig.getType() == DaoMuNpcTypeEnum.NPC_TYPE_MOBS.getType() && this.daoMuActivityConfig.checkNpcNumMax(existNpcNum)) {
                        break outer;
                    }
                }
            }
        }
        this.npcMap.putAll(npcMap);
        return npcMap;
    }

    /**
     * 生成特殊怪
     * @param second
     * @return
     */
    private Map<Long, DaoMuNpc> createNpcSpecial(int second) {
        Map<Long, DaoMuNpc> npcMap = new ConcurrentHashMap<>();
        DaoMuMissionConfig daoMuMissionConfig = this.daoMuActivityConfig.getDaoMuMissionConfigMap().get(this.passesId);
        //特殊怪 npc
        Map<String, Integer> npcConfigMap = daoMuMissionConfig.getSpecialNpc(second);
        if (npcConfigMap == null) {
            return npcMap;
        }
        //特殊怪 npc id
        int npcId = npcConfigMap.get("npcId");
        DaoMuNpcConfig daoMuNpcConfig = this.daoMuActivityConfig.getDaoMuNpcConfigMap().get(npcId);
        Map<Integer, DaoMuAttribute> attributeMap = this.daoMuActivityConfig.buildAttributeMapByNpc(daoMuNpcConfig.getBasePara());
        //判断生成NPC的数量是否达到最大值,【小怪】类型才需要判断
        int existNpcNum = this.countExistNpcNum();
        if (daoMuNpcConfig.getType() == DaoMuNpcTypeEnum.NPC_TYPE_MOBS.getType() && this.daoMuActivityConfig.checkNpcNumMax(existNpcNum)) {
            return npcMap;
        }
        //出现最大秒数
        int showEndTime = npcConfigMap.get("endTime");
        //特殊怪 npc 数量
        int npcNum = npcConfigMap.get("num");
        //一波几只怪
        int oneWaveNum = daoMuNpcConfig.getOneWaveNum();
        for (int i = 0; i < npcNum; i++) {
            //出现时间
            int showTime = randomHelper.next(second, showEndTime + 1);
            for (int x = 0; x < oneWaveNum; x++) {
                DaoMuNpc daoMuNpc = new DaoMuNpc();
                daoMuNpc.setId(this.npcMaxId.incrementAndGet());
                daoMuNpc.setNpcId(npcId);
                daoMuNpc.setStatus(DaoMuNpcStatusEnum.NPC_STATUS_EXIST.getStatus());
                daoMuNpc.setCreateTimeSecond(showTime);
                daoMuNpc.setAttributeMap(attributeMap);
                //掉落的物品，先生成好
                Property property = this.daoMuActivityConfig.getNpcDropProp(npcId);
                Map<Integer, DaoMuBattlePropItem> addBattleProp = this.addBattleProp(property, false, DaoMuPropSourceTypeEnum.DAO_MU_PROP_SOURCE_TYPE_NPC, (int) daoMuNpc.getId());
                daoMuNpc.setDropProp(addBattleProp);
                //put npc
                npcMap.put(daoMuNpc.getId(), daoMuNpc);
                //判断生成NPC的数量是否达到最大值
                existNpcNum++;
                if (this.daoMuActivityConfig.checkNpcNumMax(existNpcNum)) {
                    break;
                }
            }
        }
        this.npcMap.putAll(npcMap);
        return npcMap;
    }

    /**
     * 生成BOSS
     * @param second
     * @return
     */
    private DaoMuNpc createNpcBoss(int second) {
        Integer npcId = null;
        DaoMuMissionConfig daoMuMissionConfig = this.daoMuActivityConfig.getDaoMuMissionConfigMap().get(this.passesId);
        //判断是否达到最终boss的时间，如果是，boss还未存在，则继续刷新boss，防止卡boss的情况
        String[] bossAppearTimeArr = daoMuMissionConfig.getBossAppearTime().split("\\|");
        String[] bossIdArr = daoMuMissionConfig.getBossId().split("\\|");
        //最终boss刷新时间
        int finalTime = Integer.parseInt(bossAppearTimeArr[bossAppearTimeArr.length - 1]);
        //最终boss id
        int finalBossId = Integer.parseInt(bossIdArr[bossIdArr.length - 1]);
        //达到最终boss的时间
        if (second > finalTime) {
            boolean hasFinalBoss = false;
            //判断boss是否存在
            for (DaoMuNpc daoMuNpc : this.npcMap.values()) {
                if (daoMuNpc.getNpcId() == finalBossId) {
                    hasFinalBoss = true;
                }
            }
            //超过刷新boss时间60秒没有攻击boss伤害信息，直接刷BOSS
            if (second - finalTime >= 60 && this.stopTime == 0) {
                hasFinalBoss = false;
            }
            //没用最终boss的情况下，重新刷新boss
            if (!hasFinalBoss) {
                npcId = finalBossId;
            }
        } else {
            //boss npc
             npcId = daoMuMissionConfig.getBossNpc(second);
        }

        if (npcId == null) {
            return null;
        }

        //boss属性
        DaoMuNpcConfig daoMuNpcConfig = this.daoMuActivityConfig.getDaoMuNpcConfigMap().get(npcId);
        Map<Integer, DaoMuAttribute> attributeMap = this.daoMuActivityConfig.buildAttributeMapByNpc(daoMuNpcConfig.getBasePara());
        //生成
        DaoMuNpc daoMuNpc = new DaoMuNpc();
        daoMuNpc.setId(this.npcMaxId.incrementAndGet());
        daoMuNpc.setNpcId(npcId);
        daoMuNpc.setStatus(DaoMuNpcStatusEnum.NPC_STATUS_EXIST.getStatus());
        //掉落的物品，先生成好
        Property property = this.daoMuActivityConfig.getNpcDropProp(npcId);
        Map<Integer, DaoMuBattlePropItem> addBattleProp = this.addBattleProp(property, false, DaoMuPropSourceTypeEnum.DAO_MU_PROP_SOURCE_TYPE_NPC, (int) daoMuNpc.getId());
        daoMuNpc.setDropProp(addBattleProp);
        daoMuNpc.setCreateTimeSecond(second);
        daoMuNpc.setAttributeMap(attributeMap);
        //清理小怪，特殊怪
        this.clearNpc();
        //记录打boss开始时间
        this.battleBossStartTime = System.currentTimeMillis();
        //put boss
        this.npcMap.put(daoMuNpc.getId(), daoMuNpc);
        return daoMuNpc;
    }

    /**
     * 是否检测
     * @return
     */
    private boolean checkSwitch() {
        int checkSwitch = ChannelConfig.DAOMU_SERVER_CHECK_SWHITCH;
        if (checkSwitch == 1) {
            return true;
        }
        return false;
    }

    /**
     * 清理NPC
     * @param npcId
     */
    private void killOneNpc(long npcId) {
        //击杀计数
        this.killNpcNum.incrementAndGet();
        //清除
        this.npcMap.remove(npcId);
    }
    
    /**
     * 清理NPC
     * @param npcId
     */
    private void clearOneNpc(long npcId) {
        DaoMuNpc daoMuNpc = this.npcMap.get(npcId);
        //清除计数
        this.clearNpcNum.incrementAndGet();
        //NPC死亡
        daoMuNpc.doDie();
        //清除
        this.npcMap.remove(npcId);
    }

    /**
     * 清理NPC
     */
    private void clearNpc() {
        for (DaoMuNpc npc : this.npcMap.values()) {
            this.clearOneNpc(npc.getId());
        }
    }

    /**
     * 普通NPC伤害上报
     * @param attNpcList
     * @throws BusinessException
     */
    public void attNpc(List<DaoMuProto.DaoMuAttItem> attNpcList) {
        for (DaoMuProto.DaoMuAttItem attNpcItem : attNpcList) {
            //伤害来源
            int attHarmType = 0;
            int attHarmId = 0;
            //获取NPC对象
            DaoMuNpc daoMuNpc = this.npcMap.get(attNpcItem.getId());
            if (daoMuNpc != null && daoMuNpc.getStatus() == DaoMuNpcStatusEnum.NPC_STATUS_EXIST.getStatus()) {
                long reHp = 0;
                //获取伤害值
                if (attNpcItem.getSkillItem().getSkillId() > 0) {
                    DaoMuSkill daoMuSkill = this.activeSkillMap.get(attNpcItem.getSkillItem().getSkillId());
                    if (daoMuSkill != null && daoMuSkill.getSkillLevel() >= attNpcItem.getSkillItem().getSkillLevel()) {
                        //计算伤害用的DaoMuSkill
                        DaoMuSkill countSkill = this.getCountSkill(attNpcItem.getSkillItem().getSkillId(), attNpcItem.getSkillItem().getSkillLevel(), daoMuSkill.getCollectionId());
                        //npc的有害BUFF MAP
                        Map<Integer, DaoMuDamageBuff> damageBuffMap = this.getDamageBuffMap(attNpcItem.getSkillItem().getDamageBuffList());
                        //计算技能伤害
                        long skillReHp = this.getAttNpcHurt(countSkill, daoMuNpc, attNpcItem.getSkillItem().getOtherHarmType(), damageBuffMap, attNpcItem.getSkillItem().getMillisecond(), attNpcItem.getSkillItem().getCriticalFlag());
                        reHp += skillReHp;
                        attHarmType = DaoMuAttHarmTypeEnum.ATT_HARM_TYPE_SKILL.getType();
                        attHarmId = daoMuSkill.getSkillId();
                    }
                }
                //获取道具伤害
                if (attNpcItem.getPropItem().getBattlePropId() > 0) {
//                    long propReHp = this.getPropHurt(attNpcItem.getPropItem().getBattlePropId());
                    reHp += attNpcItem.getPropItem().getReHp();
                    attHarmType = DaoMuAttHarmTypeEnum.ATT_HARM_TYPE_PROP.getType();
                    attHarmId = attNpcItem.getPropItem().getBattlePropId();
                }
                //自爆伤害
                if (attNpcItem.getSelfBomb().getMillisecond() > 0) {
                    if (attNpcItem.getSelfBomb().getSkillId() > 0) {
                        //判断该NPC是否携带自爆技能
                        if (this.daoMuActivityConfig.checkNpcSkill(daoMuNpc.getNpcId(), attNpcItem.getSelfBomb().getSkillId())) {
                            reHp += attNpcItem.getSelfBomb().getReHp();
                            attHarmType = DaoMuAttHarmTypeEnum.ATT_HARM_TYPE_SELF_B.getType();
                            attHarmId = attNpcItem.getSelfBomb().getSkillId();
                        }
                    } else {
                        //冲刺清除，判断NPC是否有冲刺清除功能
                        if (this.daoMuActivityConfig.checkNpcHaveClear(daoMuNpc.getNpcId())) {
                            //清除
                            if (daoMuNpc.getStatus() == DaoMuNpcStatusEnum.NPC_STATUS_EXIST.getStatus()) {
                                //清除
                                daoMuNpc.setStatus(DaoMuNpcStatusEnum.NPC_STATUS_CLEAR.getStatus());
                            }
                        }
                    }
                }
                //判断是否检验伤害
                if (!this.checkSwitch()) {
                    reHp = attNpcItem.getSkillItem().getReHp();
                }

                //npc减少血量
                if (daoMuNpc.getStatus() == DaoMuNpcStatusEnum.NPC_STATUS_EXIST.getStatus()) {
                    daoMuNpc.reHp(reHp);
                    //记录NPC收到的伤害
                    daoMuNpc.addHarm(attHarmType, attHarmId, reHp);
                    if (daoMuNpc.isDie()) {
                        this.npcDieHandle(daoMuNpc.getNpcId());
                    }
                }
            }
        }
    }

    /**
     * 获取伤害计算的DaoMuSkill
     * @param skillId
     * @param skillLevel
     * @param collectionId
     * @return
     */
    private DaoMuSkill getCountSkill(int skillId, int skillLevel, int collectionId) {
        DaoMuSkill countSkill = new DaoMuSkill();
        countSkill.setSkillId(skillId);
        countSkill.setSkillLevel(skillLevel);
        countSkill.setCollectionId(collectionId);
        if (skillLevel >= Integer.parseInt(this.daoMuActivityConfig.getDaoMuActivityConfigValue(eActivityConfigType.DAOMU_LNNING_HAS_ASSISTIVE_SKILL_LEVEL_MAX))) {
            countSkill.setFullLevelFlag(true);
        }
        return countSkill;
    }

    /**
     * 获取损害buff map
     * @param daoMuDamageBuffList
     * @return
     */
    private Map<Integer, DaoMuDamageBuff> getDamageBuffMap(List<DaoMuProto.DaoMuDamageBuff> daoMuDamageBuffList) {
        Map<Integer, DaoMuDamageBuff> map = new HashMap<>();
        for (DaoMuProto.DaoMuDamageBuff daoMuDamageBuff : daoMuDamageBuffList) {
            DaoMuDamageBuff damageBuff = map.get(daoMuDamageBuff.getBuffType());
            if (damageBuff == null) {
                damageBuff = new DaoMuDamageBuff();
                damageBuff.setBuffType(daoMuDamageBuff.getBuffType());
                damageBuff.setBuffValue(daoMuDamageBuff.getBuffValue());
                map.put(damageBuff.getBuffType(), damageBuff);
            } else {
                damageBuff.addValue(daoMuDamageBuff.getBuffValue());
            }
        }
        return map;
    }

    /**
     * npc死亡处理
     * @param npcId
     */
    private void npcDieHandle(int npcId) {
        //判断是否是悬赏NPC
        if (this.daoMuActivityConfig.checkIsOfferRewardNpc(this.passesId, npcId)) {
            this.offerRewardNpcIdSet.add(npcId);
        }
        //清理NPC
        this.killOneNpc(npcId);
    }

    /**
     * 升级校验
     * @param clientExp 客户端经验
     * @param expStoneList 经验石列表
     * @param gameMillisecond 游戏进行秒数
     * @return
     */
    public List<DaoMuSkill> upgrade(int clientExp, List<DaoMuProto.DaoMuExpStoneItem> expStoneList, int gameMillisecond) {
        //判断是否已经达到最大等级
        if (this.level >= this.daoMuActivityConfig.getMaxLevel()) {
            return null;
        }
        //是否服务端检验。特色服不校验
        if (this.checkSwitch() && this.daoMuActivityConfig.getActivityInfo().getType() == eActivityType.DaoMu.getValue()) {
            int addExp = 0;//经验
            for (DaoMuProto.DaoMuExpStoneItem expStoneItem : expStoneList) {
                //局内道具对象
                DaoMuBattlePropItem battleProp = this.battlePropMap.get(expStoneItem.getBattlePropId());
                if (battleProp != null && this.useProp(battleProp)) {
                    //增加多少经验
                    int addSingleExp = this.daoMuActivityConfig.getExpStoneExp(battleProp.getCurioId());
                    //经验增加BUFF
                    addSingleExp = this.buffHandlerExpRateAdd(addSingleExp);
                    addExp += addSingleExp;
                }
            }
            //获取自动增加的经验
            int autoAddExp = this.buffHandlerExpAutoAdd(gameMillisecond);
            this.exp += autoAddExp;
            //获取新经验，新等级
            this.exp += addExp;
        } else {
            this.exp = clientExp;
        }
        int newLevel = this.daoMuActivityConfig.getLevelByExp(this.exp);

        //判断是否升级
        if (newLevel > this.level) {
            //升级
            this.level = newLevel;
            //存储，为了选择的时候校验
            this.waitSelectSkillNum.incrementAndGet();
            //获取待选择技能
            //判断是否只出主动技能
            int activeTime = Integer.parseInt(this.daoMuActivityConfig.getDaoMuActivityConfigValue(eActivityConfigType.DAOMU_LNNING_MUST_HAVE_ACTIVE_SKILL_NUM));
            boolean activeFlag = false;
            if (newLevel - 1 <= activeTime) {
                activeFlag = true;
            }
            return this.getSelectSkillList(activeFlag);
        }
        return null;
    }

    /**
     * 刷新技能选择列表
     * @param gamePlayer
     * @return
     * @throws BusinessException
     */
    public List<DaoMuSkill> randomSelectSkillList(GamePlayer gamePlayer) throws BusinessException {
        //判断次数是否足够
        int allRandomNum = Integer.parseInt(daoMuActivityConfig.getDaoMuActivityConfigValue(eActivityConfigType.DAOMU_LNNING_SKILL_REFRESH_NUM_MAX));
        if (this.randomSelectSkillNum >= allRandomNum) {
            throw BusinessException.newException(GameErrorCode.E_DAOMU_RANDOM_SELECT_SKILL_NUM_NOT_ENOUGH);
        }
        //消耗元宝
        int costGoodsId = GameConfig.GAME_MONEY_INGOTS;
        long costNum = this.daoMuActivityConfig.getRandomSkillCostNum(this.randomSelectSkillNum);
        Property property = new Property();
        property.setGood(costGoodsId, BigInteger.valueOf(costNum));
        boolean costResult = gamePlayer.getModule(CurrencyModule.class).removeCurrency(property, eLogMoneyType.DaoMu, eLogMoneyType.DaoMuRandomSelectSkillListCost);
        if (!costResult) {
            throw BusinessException.newException(GameErrorCode.E_DAOMU_RANDOM_INGOTS_NOT_ENOUGH);
        }
        //增加随机选择次数
        this.randomSelectSkillNum++;
        //重新随机技能
        return this.getSelectSkillList(false);
    }

    /**
     * 获取待选择技能
     * @param activeFlag 是否只出主动技能
     * @return
     */
    private List<DaoMuSkill> getSelectSkillList(boolean activeFlag) {
        //获取技能选择list
        List<DaoMuSkill> list = this.daoMuActivityConfig.getSkillSelectList(this.activeSkillMap, this.passiveSkillMap, this.unlockSkillListMap, activeFlag);
        for (DaoMuSkill skill : list) {
            //获取技能下一个等级配置
            int nextLevel = 1;
            if (this.activeSkillMap.containsKey(skill.getSkillId()) || this.passiveSkillMap.containsKey(skill.getSkillId())) {
                DaoMuSkillConfig nextSkillConfig = this.getRealDaoMuSkillConfig(skill.getSkillId(), skill.getSkillLevel() + 1);
                nextLevel = nextSkillConfig.getLevel();
            } else {
                if (this.unlockSkillListMap.containsKey(skill.getSkillId())) {
                    DaoMuSkillConfig nextSkillConfig = this.getRealDaoMuSkillConfig(skill.getSkillId(), skill.getSkillLevel());
                    nextLevel = nextSkillConfig.getLevel();
                }
            }
            skill.setNextLevel(nextLevel);
        }
        return list;
    }

    /**
     * 升级后选择技能
     * @param skillId 技能ID
     * @param gameMillisecond 游戏进行毫秒数
     * @throws BusinessException
     */
    public void upgradeSelectSkill(int skillId, int gameMillisecond) throws BusinessException {
        if (this.waitSelectSkillNum.get() > 0) {
            //减少次数
            this.waitSelectSkillNum.decrementAndGet();
            //升级
            this.upgradeSkill(skillId, gameMillisecond);
        }
    }

    /**
     * 技能升级
     * @param skillId 技能ID
     * @param gameMillisecond 游戏进行毫秒数
     */
    public DaoMuSkill upgradeSkill(int skillId, int gameMillisecond) {
        //自动回血一下
        this.buffHandlerHpAutoAdd(gameMillisecond);
        //判断是否是止血散
        DaoMuCurioConfig daoMuCurioConfig = this.daoMuActivityConfig.getDaoMuCurioConfigMap().get(skillId);
        if (daoMuCurioConfig != null && daoMuCurioConfig.getType() == DaoMuCurioTypeEnum.TYPE_STOP_BLEED.getType()) {
            //回血
            long recoverHp = this.daoMuActivityConfig.getPropRecoverHp(skillId, this.getTotalHp());
            this.addHp(recoverHp);
            DaoMuSkill daoMuSkill = new DaoMuSkill();
            daoMuSkill.setSkillId(skillId);
            return daoMuSkill;
        } else {
            //技能配置
            DaoMuSkill unLockSkill = this.unlockSkillListMap.get(skillId);
            DaoMuSkillConfig daoMuSkillConfig = this.daoMuActivityConfig.getSkillConfig(unLockSkill.getSkillId(), unLockSkill.getSkillLevel());
            //选择技能
            Map<Integer, DaoMuSkill> skillMap;
            if (daoMuSkillConfig.getType() == DaoMuCurioSmallTypeEnum.SMALL_TYPE_ATT.getType()) {
                skillMap = this.activeSkillMap;
            } else {
                skillMap = this.passiveSkillMap;
            }
            DaoMuSkill daoMuSkill = skillMap.get(skillId);
            if (daoMuSkill != null) {
                //判断技能是否满级
                boolean fullLevel;
                if (daoMuSkillConfig.getType() == DaoMuCurioSmallTypeEnum.SMALL_TYPE_ATT.getType()) {
                    fullLevel = this.daoMuActivityConfig.checkActiveSkillLevelFull(daoMuSkill, this.passiveSkillMap);
                } else {
                    fullLevel = this.daoMuActivityConfig.checkPassiveSkillLevelFull(daoMuSkill.getSkillLevel());
                }
                if (!fullLevel) {
                    //升级
                    int newLevel = daoMuSkill.getSkillLevel() + 1;
                    DaoMuSkillConfig nextSkill = this.daoMuActivityConfig.getSkillConfig(skillId, newLevel);
                    if (nextSkill != null) {
                        daoMuSkill.setSkillLevel(newLevel);
                        if (newLevel >= Integer.parseInt(this.daoMuActivityConfig.getDaoMuActivityConfigValue(eActivityConfigType.DAOMU_LNNING_HAS_ASSISTIVE_SKILL_LEVEL_MAX))) {
                            daoMuSkill.setFullLevelFlag(true);
                        }
                    }
                }
            } else {
                daoMuSkill = unLockSkill;
            }
            daoMuSkill.setGameMillisecond(gameMillisecond);
            skillMap.put(skillId, daoMuSkill);
            return daoMuSkill;
        }
    }

    /**
     * 攻击boss
     * @param attItem
     * @return
     */
    private DaoMuNpc attBoss(DaoMuAttItem attItem) {
        DaoMuNpc boss =  this.npcMap.get(attItem.getNpcUnId());
        if (boss != null && boss.getStatus() == DaoMuNpcStatusEnum.NPC_STATUS_EXIST.getStatus()) {
            DaoMuNpcConfig daoMuNpcConfig = this.daoMuActivityConfig.getDaoMuNpcConfigMap().get(boss.getNpcId());
            if (daoMuNpcConfig != null && daoMuNpcConfig.getType() == DaoMuNpcTypeEnum.NPC_TYPE_BOSS.getType()) {
                //获取伤害值
                DaoMuSkill daoMuSkill = this.activeSkillMap.get(attItem.getSkillId());
                long reHp = 0;
                //是否服务端计算伤害
                if (this.checkSwitch()) {
                    if (daoMuSkill != null && daoMuSkill.getSkillLevel() >= attItem.getSkillLevel()) {
                        //计算伤害用的DaoMuSkill
                        DaoMuSkill countSkill = this.getCountSkill(attItem.getSkillId(), attItem.getSkillLevel(), daoMuSkill.getCollectionId());
                        //计算伤害
                        reHp = this.getAttNpcHurt(countSkill, boss, attItem.getSkillHarmType(), attItem.getDamageBuffMap(), attItem.getGameMillisecond(), attItem.isCriticalFlag());
                    }
                } else {
                    reHp = attItem.getReHp();
                }
                //npc减少血量
                boss.reHp(reHp);
                //判断是否死亡
                if (boss.isDie()) {
                    //npc死亡处理
                    this.npcDieHandle(boss.getNpcId());
                    //计算攻击boss时长
                    long attBossTime = System.currentTimeMillis() - this.battleBossStartTime;
                    this.battleBossTime += attBossTime;
                    //判断是否过关
                    boolean finalBossFlag = this.daoMuActivityConfig.checkFinalBoss(this.passesId, boss.getNpcId());
                    if (finalBossFlag) {
                        //结算
                        DaoMuStatementInfo daoMuStatementInfo = new DaoMuStatementInfo();
                        daoMuStatementInfo.setStatus(true);
                        daoMuStatementInfo.setBattleTime(this.countBattleTime());
                        daoMuStatementInfo.setKillNum(this.countKillNpcNum());
                        this.daoMuStatementInfo = daoMuStatementInfo;
                    }
                }
            }
        }
        return boss;
    }

    /**
     * 被攻击
     * @param daoMuAttItem
     */
    private void beAtt(DaoMuAttItem daoMuAttItem) {
        //回血
        this.buffHandlerHpAutoAdd(daoMuAttItem.getGameMillisecond());
        //获取NPC
        DaoMuNpc npc =  this.npcMap.get(daoMuAttItem.getNpcUnId());
        if (npc == null || npc.getStatus() != DaoMuNpcStatusEnum.NPC_STATUS_EXIST.getStatus()) {
            return;
        }
        DaoMuNpcConfig daoMuNpcConfig = this.daoMuActivityConfig.getDaoMuNpcConfigMap().get(npc.getNpcId());
        if (daoMuNpcConfig == null) {
            return;
        }
        if (daoMuAttItem.getReHp() <= 0) {
            return;
        }
        //获取技能配置,npc技能ID客户端传过来的是 技能配置表的唯一ID
        DaoMuSkillConfig daoMuSkillConfig = this.daoMuActivityConfig.getDaoMuSkillConfigMap().get(daoMuAttItem.getSkillId());
        if (daoMuSkillConfig == null) {
            return;
        }
        //计算技能伤害
        long reHp;
        //是否服务端计算伤害
        if (this.checkSwitch()) {
            reHp = this.getBeAttHurt(daoMuAttItem.getSkillId(), npc, daoMuAttItem.getSkillHarmType(), daoMuAttItem.getDamageBuffMap(), daoMuAttItem.getGameMillisecond(), daoMuAttItem.isCriticalFlag());
        } else {
            reHp = daoMuAttItem.getReHp();
        }
        this.reduceHp(reHp);
    }

    /**
     * 攻击上报
     * @param attBossList
     * @param beAttList
     */
    public DaoMuAttReportRes attReport(List<DaoMuProto.DaoMuAttItem> attBossList, List<DaoMuProto.DaoMuAttItem> beAttList) {
        DaoMuAttReportRes result = new DaoMuAttReportRes();
        if (this.daoMuStatementInfo != null) {
            return result;
        }
        List<DaoMuAttItem> attList = new ArrayList<>();
        //攻击BOSS
        for (DaoMuProto.DaoMuAttItem daoMuAttItem : attBossList) {
            DaoMuAttItem attItem = this.createAttItem(daoMuAttItem, DaoMuAttTypeEnum.ATT_TYPE_ATT_BOSS);
            attList.add(attItem);
        }
        //被攻击
        for (DaoMuProto.DaoMuAttItem daoMuAttItem : beAttList) {
            DaoMuAttItem attItem = this.createAttItem(daoMuAttItem, DaoMuAttTypeEnum.ATT_TYPE_BE_ATT);
            attList.add(attItem);
        }
        //排序
        attList.sort(Comparator.comparingLong(DaoMuAttItem::getTime));

        DaoMuMissionConfig daoMuMissionConfig = this.daoMuActivityConfig.getDaoMuMissionConfigMap().get(this.passesId);
        //判断是否达到最终boss的时间，如果是，boss还未存在，则继续刷新boss，防止卡boss的情况
        String[] bossAppearTimeArr = daoMuMissionConfig.getBossAppearTime().split("\\|");
        String[] bossIdArr = daoMuMissionConfig.getBossId().split("\\|");
        //最终boss刷新时间
        int finalTime = Integer.parseInt(bossAppearTimeArr[bossAppearTimeArr.length - 1]);
        //最终boss id
        int finalBossId = Integer.parseInt(bossIdArr[bossIdArr.length - 1]);

        //遍历计数伤害
        DaoMuNpc boss = null;
        for (DaoMuAttItem attItem : attList) {
            if (attItem.getType() == DaoMuAttTypeEnum.ATT_TYPE_ATT_BOSS.getType()) {
                //攻击BOSS
                boss = this.attBoss(attItem);
            } else {
                //被攻击
                this.beAtt(attItem);
            }

            //判断是否是最终BOSS,记录攻击boss次数
            DaoMuNpc daoMuNpc = this.npcMap.get(attItem.getNpcUnId());
            if (daoMuNpc != null && daoMuNpc.getNpcId() == finalBossId) {
                //是否已经在最终boss的出现时间里
                if (attItem.getGameMillisecond() > finalTime * 1000) {
                    this.stopTime++;
                }
            }

            if (this.daoMuStatementInfo != null) {
                break;
            }
        }
        result.setBoss(boss);
        return result;
    }

    /**
     * 构造 DaoMuAttItem
     * @param daoMuAttItem
     * @param daoMuAttTypeEnum
     * @return
     */
    private DaoMuAttItem createAttItem(DaoMuProto.DaoMuAttItem daoMuAttItem, DaoMuAttTypeEnum daoMuAttTypeEnum) {
        DaoMuAttItem attItem = new DaoMuAttItem();
        attItem.setNpcUnId(daoMuAttItem.getId());
        attItem.setSkillId(daoMuAttItem.getSkillItem().getSkillId());
        attItem.setSkillHarmType(daoMuAttItem.getSkillItem().getOtherHarmType());
        attItem.setReHp(daoMuAttItem.getSkillItem().getReHp());
        attItem.setTime(daoMuAttItem.getSkillItem().getTime());
        attItem.setType(daoMuAttTypeEnum.getType());
        //npc的有害BUFF MAP
        Map<Integer, DaoMuDamageBuff> damageBuffMap = this.getDamageBuffMap(daoMuAttItem.getSkillItem().getDamageBuffList());
        attItem.setDamageBuffMap(damageBuffMap);
        attItem.setGameMillisecond(daoMuAttItem.getSkillItem().getMillisecond());
        attItem.setCriticalFlag(daoMuAttItem.getSkillItem().getCriticalFlag());
        attItem.setSkillLevel(daoMuAttItem.getSkillItem().getSkillLevel());
        return attItem;
    }

    /**
     * 打破陶罐
     * @return
     * @throws BusinessException
     */
    public Map<Integer, DaoMuBattlePropItem> breakClay(int battlePropId) throws BusinessException{
        //判断陶罐是否存在
        DaoMuBattlePropItem daoMuBattlePropItem = this.battlePropMap.get(battlePropId);
//        logger.debug("打破陶罐：{}, {}", battlePropId, daoMuBattlePropItem);
        if (daoMuBattlePropItem == null) {
            throw BusinessException.newException(GameErrorCode.E_DAOMU_PVE_CLAY_NOT_EXIST_ERROR);
        }
        DaoMuCurioConfig daoMuCurioConfig = this.daoMuActivityConfig.getDaoMuCurioConfigMap().get(daoMuBattlePropItem.getCurioId());
        if (daoMuCurioConfig == null || daoMuCurioConfig.getType() != DaoMuCurioTypeEnum.TYPE_CLAY.getType()) {
            throw BusinessException.newException(GameErrorCode.E_DAOMU_PVE_CLAY_NOT_EXIST_ERROR);
        }
        //使用陶罐
        DaoMuBattlePropItem battleProp = this.battlePropMap.get(battlePropId);
        if (battleProp == null || !this.useProp(battleProp)) {
            throw BusinessException.newException(GameErrorCode.E_DAOMU_PVE_CLAY_NOT_EXIST_ERROR);
        }
        //掉落的道具
        Property property = PropertyHelper.parseNewStringToProperty(daoMuCurioConfig.getAttributePara());
        //添加局内道具
        return this.addBattleProp(property, true, DaoMuPropSourceTypeEnum.DAO_MU_PROP_SOURCE_TYPE_BREAK_CLAY, battlePropId);
    }

    /**
     * 捡起道具
     * @param battlePropId
     * @throws BusinessException
     */
    public DaoMuBattlePropItem pickUpProp(int battlePropId) throws BusinessException {
        DaoMuBattlePropItem daoMuBattlePropItem = this.battlePropMap.get(battlePropId);
        //判断道具是否存在
        DaoMuBattlePropItem battleProp = this.battlePropMap.get(battlePropId);
        if (battleProp == null) {
            throw BusinessException.newException(GameErrorCode.E_DAOMU_PVE_PROP_NOT_EXIST_ERROR);
        }
        DaoMuCurioConfig daoMuCurioConfig = this.daoMuActivityConfig.getCurioConfig(battleProp.getCurioId());
        if (daoMuCurioConfig == null) {
            throw BusinessException.newException(GameErrorCode.E_DAOMU_PVE_PROP_NOT_EXIST_ERROR);
        }
        if (!this.useProp(battleProp)) {
            throw BusinessException.newException(GameErrorCode.E_DAOMU_PVE_PROP_NOT_EXIST_ERROR);
        }
        //使用
        if (daoMuCurioConfig.getType() == DaoMuCurioTypeEnum.TYPE_STOP_BLEED.getType()) {
            //回血
            long recoverHp = this.daoMuActivityConfig.getPropRecoverHp(daoMuCurioConfig.getId(), this.getTotalHp());
            this.addHp(recoverHp);
        }
        return daoMuBattlePropItem;
    }

//    /**
//     * 捡起宝箱
//     * @param battlePropId 宝箱ID
//     * @param gameMillisecond 游戏进行毫秒数
//     * @return
//     * @throws BusinessException
//     */
//    public DaoMuOpenBoxRes pickUpBox(int battlePropId, int gameMillisecond) throws BusinessException {
//        //判断宝箱是否存在
//        DaoMuBattlePropItem daoMuBattlePropItem = this.battlePropMap.get(battlePropId);
//        if (daoMuBattlePropItem == null || daoMuBattlePropItem.getCurioId() != this.daoMuActivityConfig.getBoxId()) {
//            throw BusinessException.newException(GameErrorCode.E_DAOMU_PVE_BOX_NOT_EXIST_ERROR);
//        }
//        //判断道具是否存在
//        DaoMuBattlePropItem battleProp = this.battlePropMap.get(battlePropId);
//        if (battleProp == null || !battleProp.use()) {
//            throw BusinessException.newException(GameErrorCode.E_DAOMU_PVE_BOX_NOT_EXIST_ERROR);
//        }
//        //进行宝箱抽取
//        DaoMuOpenBoxRes daoMuOpenBoxRes = this.daoMuActivityConfig.openBoxSkillList(this.activeSkillMap, this.passiveSkillMap, this.unlockSkillListMap);
//        //增加升级技能
//        for (DaoMuSkill daoMuSkill : daoMuOpenBoxRes.getSelectedSkillList()) {
//            this.upgradeSkill(daoMuSkill.getSkillId(), gameMillisecond);
//        }
//        return daoMuOpenBoxRes;
//    }

    /**
     * 捡起宝箱
     * @param battlePropId 宝箱ID
     * @param gameMillisecond 游戏进行毫秒数
     * @return
     * @throws BusinessException
     */
    public DaoMuOpenBoxRes pickUpBox(int battlePropId, int gameMillisecond) throws BusinessException {
        //特色服不校验
        if (this.daoMuActivityConfig.getActivityInfo().getType() == eActivityType.DaoMu.getValue()) {
            //判断宝箱是否存在
            DaoMuBattlePropItem daoMuBattlePropItem = this.battlePropMap.get(battlePropId);
            if (daoMuBattlePropItem == null || daoMuBattlePropItem.getCurioId() != this.daoMuActivityConfig.getBoxId()) {
                throw BusinessException.newException(GameErrorCode.E_DAOMU_PVE_BOX_NOT_EXIST_ERROR);
            }
            //使用宝箱
            if (!this.useProp(daoMuBattlePropItem)) {
                throw BusinessException.newException(GameErrorCode.E_DAOMU_PVE_BOX_NOT_EXIST_ERROR);
            }
        }
        //构造返回
        List<DaoMuSkill> selectedSkillList = new ArrayList<>();

        //进行宝箱抽取
        DaoMuBoxSelectSkill daoMuBoxSelectSkill = this.daoMuActivityConfig.getBoxSkillIdList(this.activeSkillMap, this.passiveSkillMap, this.unlockSkillListMap);

        //构造16技能选择框
        DaoMuOpenBoxRes daoMuOpenBoxRes = new DaoMuOpenBoxRes();
        List<DaoMuSkill> allSkillList = this.createBoxSelectList(daoMuBoxSelectSkill.getAllSkillIdList());

        //升级
        for (int skillId : daoMuBoxSelectSkill.getSelectSkillIdList()) {
            DaoMuSkill daoMuSkill = this.upgradeSkill(skillId, gameMillisecond);
            //返回结果
            DaoMuSkill addDaoMuSkill = new DaoMuSkill();
            addDaoMuSkill.setSkillId(skillId);
            addDaoMuSkill.setSkillLevel(daoMuSkill.getSkillLevel());
            selectedSkillList.add(addDaoMuSkill);
        }

        daoMuOpenBoxRes.setAllSkillList(allSkillList);
        daoMuOpenBoxRes.setSelectedSkillList(selectedSkillList);
        return daoMuOpenBoxRes;
    }

    /**
     * 构造宝箱选择技能池等级
     * @param skillIdList 技能池ID
     * @return
     */
    private List<DaoMuSkill> createBoxSelectList(List<Integer> skillIdList) {
        Map<Integer, Integer> skillLevelMap = new HashMap<>();
        List<DaoMuSkill> result = new ArrayList<>();
        for (int skillId : skillIdList) {
            DaoMuSkill unLockSkill = this.unlockSkillListMap.get(skillId);
            //回血散
            if (unLockSkill == null) {
                //回血散
                DaoMuSkill info = new DaoMuSkill();
                info.setSkillId(skillId);
                info.setSkillLevel(1);
                result.add(info);
                continue;
            }
            DaoMuSkillConfig daoMuSkillConfig = this.daoMuActivityConfig.getSkillConfig(unLockSkill.getSkillId(), unLockSkill.getSkillLevel());
            //已学习的技能池
            Map<Integer, DaoMuSkill> skillMap;
            if (daoMuSkillConfig.getType() == DaoMuCurioSmallTypeEnum.SMALL_TYPE_ATT.getType()) {
                skillMap = this.activeSkillMap;
            } else {
                skillMap = this.passiveSkillMap;
            }
            DaoMuSkill daoMuSkill = skillMap.get(skillId);
            //不存在的技能注入等级1，存在的技能等级+1
            Integer level = skillLevelMap.get(skillId);
            int skillLevel;
            if (level == null) {
                if (daoMuSkill == null) {
                    skillLevel = 1;
                } else {
                    skillLevel = daoMuSkill.getSkillLevel() + 1;
                }
            } else {
                skillLevel = level + 1;
            }
            //记录技能和等级关系
            skillLevelMap.put(skillId, skillLevel);
            //构造返回
            //获取觉醒等级
            DaoMuSkill info = new DaoMuSkill();
            DaoMuSkillConfig realSkill = this.getRealDaoMuSkillConfig(skillId, skillLevel);
            if (realSkill != null) {
                info.setSkillLevel(realSkill.getLevel());
            } else {
                info.setSkillLevel(skillLevel);
            }
            info.setSkillId(skillId);
            result.add(info);
        }
        return result;
    }

    /**
     * 生成陶罐
     * @param position
     * @return
     */
    public int createClay(String position) {
        //判断该坐标的陶罐是否已经存在
        if (this.clayPositionSet.contains(position)) {
            return 0;
        }
        // rate / 1000 的概率才会生成陶罐
        int rate = Integer.parseInt(this.daoMuActivityConfig.getDaoMuActivityConfigValue(eActivityConfigType.DAOMU_CLAY_POT_WEIGHTS));
        int randomResult = randomHelper.next(1, 1001);
        if (randomResult > rate) {
            return 0;
        }
        //生成陶罐，记录生成坐标
        int clayPropId = this.daoMuActivityConfig.getClayCurioId();
        Map<Integer, DaoMuBattlePropItem> battleProp = this.addBattleProp(clayPropId, 1, true, DaoMuPropSourceTypeEnum.DAO_MU_PROP_SOURCE_TYPE_CREATE_CLAY, 0);
        clayPositionSet.add(position);
        for (DaoMuBattlePropItem battlePropItem : battleProp.values()) {
            return battlePropItem.getBattlePropId();
        }
        return 0;
    }

    /**
     * 计算游戏时长
     * @return
     */
    public long countBattleTime() {
        return System.currentTimeMillis() - this.createTime;
    }

    /**
     * 计算杀NPC数
     * @return
     */
    public int countKillNpcNum() {
        return this.killNpcNum.get();
    }

    /**
     * 计算存活的NPC数
     * @return
     */
    private int countExistNpcNum() {
        int num = 0;
        for (DaoMuNpc daoMuNpc : this.npcMap.values()) {
            if (daoMuNpc.getStatus() == DaoMuNpcStatusEnum.NPC_STATUS_EXIST.getStatus()) {
                num++;
            }
        }
        return num;
    }

    /**
     * 获取技能集合，；号隔开
     * @return
     */
    public String getSkillIds() {
        List<Integer> activeSkillIds = new ArrayList<>(this.activeSkillMap.keySet());
        List<Integer> passiveSkillIds = new ArrayList<>(this.passiveSkillMap.keySet());
        activeSkillIds.addAll(passiveSkillIds);
        return StringUtils.listToString(activeSkillIds, ";");
    }

    /**
     * 复活
     */
    public void doResurgence() {
        //回满血
        this.reduceHp = 0;
        //复活次数加1
        this.resurgenceNum++;
        //清空结算
        this.daoMuStatementInfo = null;
    }

    /************************************************技能BUFF****************************************************/

    /**
     * BUFF:经验加成
     * @param exp
     * @return
     */
    private int buffHandlerExpRateAdd(int exp) {
        long addRate = 0;
        //辅助技能-八重宝函
        DaoMuSkill daoMuSkill = passiveSkillMap.get(DaoMuSkillEnum.DAO_MU_SKILL_20400.getId());
        if (daoMuSkill != null) {
            //获取技能配置
            DaoMuSkillConfig daoMuSkillConfig = this.getRealDaoMuSkillConfig(daoMuSkill);
            String[] skillParaArr = daoMuSkillConfig.getSkillPara().split("\\|");
            //增加经验获取千分比
            addRate += Long.parseLong(skillParaArr[16]);
        }
        //计算最终经验
        BigDecimal rateBig = BigDecimal.valueOf(addRate + 1000).divide(BigDecimal.valueOf(1000));
        BigDecimal valueBig = BigDecimal.valueOf(exp).multiply(rateBig) ;
        return valueBig.intValue();
    }

    /**
     * BUFF:经验自动增加
     * @Param gameMillisecond 当前游戏进行的毫秒数
     * @return
     */
    private int buffHandlerExpAutoAdd(int gameMillisecond) {
        int exp = 0;
        //辅助技能-八重宝函
        DaoMuSkill daoMuSkill = passiveSkillMap.get(DaoMuSkillEnum.DAO_MU_SKILL_20400.getId());
        if (daoMuSkill != null) {
            //获取技能配置
            DaoMuSkillConfig daoMuSkillConfig = this.getRealDaoMuSkillConfig(daoMuSkill);
            String[] skillParaArr = daoMuSkillConfig.getSkillPara().split("\\|");
            //加经验
            String paramStr = skillParaArr[17];
            if (!StringUtils.isNullOrEmpty(paramStr) && !paramStr.equals("0")) {
                String[] paramArr = paramStr.split(";");
                int addExp = Integer.parseInt(paramArr[0]);//一次加多少
                int addNumTime = Integer.parseInt(paramArr[1]);//多长时间加一次
                //计算距离上次自动加经验，经历了多少毫秒
                int lastAutoAddExpTime = this.lastAutoAddExpTime == 0 ? daoMuSkill.getGameMillisecond() : this.lastAutoAddExpTime;
                int diffTime = gameMillisecond - lastAutoAddExpTime;
                int addNum = diffTime / addNumTime;
                if (addNum > 0) {
                    //记录上次增加自动经验时间
                    this.lastAutoAddExpTime = gameMillisecond;
                }
                exp = addExp * addNum;
            }
        }
        return exp;
    }

    /**
     * BUFF:自动回血
     * @param gameMillisecond 游戏进行时间
     */
    private void buffHandlerHpAutoAdd(int gameMillisecond) {
        //最大血量
        long maxHp = this.getTotalHp();
        //基础自动回血
        DaoMuAttribute recoverHpAttribute = this.getAttributeMap().get(DaoMuAttributeEnum.ATTRIBUTE_RECOVER_HP_PVE.getType());
        long recoverHpRate = recoverHpAttribute.getValue().longValue();
        //辅助技能-玉俑
        DaoMuSkill daoMuSkill = passiveSkillMap.get(DaoMuSkillEnum.DAO_MU_SKILL_21200.getId());
        if (daoMuSkill != null) {
            //技能配置
            DaoMuSkillConfig daoMuSkillConfig = this.getRealDaoMuSkillConfig(daoMuSkill);
            String[] skillParaArr = daoMuSkillConfig.getSkillPara().split("\\|");
            //提升回血千分比
            long addRate = Long.parseLong(skillParaArr[32]);
            //回血属性
            recoverHpRate += addRate;
        }
        //一次回多少血
        BigDecimal oneRecoverHpBig = BigDecimal.valueOf(maxHp).multiply(BigDecimal.valueOf(recoverHpRate).divide(BigDecimal.valueOf(1000)));
        long oneRecoverHp = oneRecoverHpBig.longValue();
        //多少时间回一次血
        String cdStr = this.daoMuActivityConfig.getDaoMuActivityConfigValue(eActivityConfigType.DAOMU_PARTNER_BASE_PARA_RETURN_HP_CD);
        int cd = Integer.parseInt(cdStr);
        //计算距离上次自动回血，经历了多少毫秒
        int diffTime = gameMillisecond - this.lastAutoAddHpTime;
        //加多少次
        int addNum = diffTime / cd;
        //一次加多少 * 加多少次
        long recoverHp = oneRecoverHp * addNum;
        if (recoverHp > 0) {
            //记录回血时间
            this.lastAutoAddHpTime = gameMillisecond;
        }
        //进行回血
        this.addHp(recoverHp);
    }

    /**
     * BUFF:受伤回血
     */
    private void buffHandlerHarmHpAdd() {
        //辅助技能-陨玉
        DaoMuSkill daoMuSkill = passiveSkillMap.get(DaoMuSkillEnum.DAO_MU_SKILL_21300.getId());
        if (daoMuSkill != null) {
            //获取技能配置
            DaoMuSkillConfig daoMuSkillConfig = this.getRealDaoMuSkillConfig(daoMuSkill);
            String[] skillParaArr = daoMuSkillConfig.getSkillPara().split("\\|");
            String paramStr = skillParaArr[35];
            if (!StringUtils.isNullOrEmpty(paramStr) && !paramStr.equals("0")) {
                String[] paramArr = paramStr.split(";");
                //回血千分比
                long recoverHpRate = Long.parseLong(paramArr[1]);
                //最大血量
                long maxHp = this.getTotalHp();
                //一次回多少血
                BigDecimal recoverHpBig = BigDecimal.valueOf(maxHp).multiply(BigDecimal.valueOf(recoverHpRate).divide(BigDecimal.valueOf(1000)));
                long recoverHp = recoverHpBig.longValue();
                //回血
                this.addHp(recoverHp);
            }
        }
    }

    /**
     * BUFF: 增加最大生命值
     */
    private BigDecimal buffHandlerMaxHpAdd(BigDecimal maxHp) {
        //辅助技能-陨玉
        DaoMuSkill daoMuSkill = passiveSkillMap.get(DaoMuSkillEnum.DAO_MU_SKILL_21300.getId());
        if (daoMuSkill != null) {
            //获取技能配置
            DaoMuSkillConfig daoMuSkillConfig = this.getRealDaoMuSkillConfig(daoMuSkill);
            String[] skillParaArr = daoMuSkillConfig.getSkillPara().split("\\|");
            String paramStr = skillParaArr[34];
            if (!StringUtils.isNullOrEmpty(paramStr) && !paramStr.equals("0")) {
                //增加最大血量千分比
                long addRate = Long.parseLong(paramStr);
                //计算最新最大血量
                return maxHp.multiply(BigDecimal.valueOf(addRate + 1000).divide(BigDecimal.valueOf(1000)));
            }
        }
        return maxHp;
    }

    /************************************************技能BUFF****************************************************/
}
